昨天說工具只是一張能力清單,agent 真正跑起來靠的是一個循環:模型看著當前的 context 決定下一步、系統執行它選的工具、結果回到窗口、模型再決定下一步,直到任務完成。這個「思考、行動、觀察」的節奏在文獻裡叫 ReAct,整個循環就是 agentic loop,agent 的心臟。先把名字說清楚,免得跟 Day 1 地圖上的 L4 撞名:這裡的 loop 是一次執行之內的迴圈;L4 Loop Engineering 講的是跨執行的改進迴路,兩個 loop 各管各的尺度。
大多數人的第一版 loop 都長這樣,我自己的也是:
while True:
response = call_llm(messages)
if response.tool_calls:
messages.append(execute_tools(response.tool_calls))
else:
return response.content
這個版本 demo 跑得很好。後來我讓它跑一個複雜任務,多個工具、幾十輪迭代,它在第三十幾輪靜默掛掉:沒有 error、沒有 log,就停在那裡。問題出在這個 loop 只寫了 happy path:出錯之後怎麼辦、什麼情況該停、跑到一半有人想介入怎麼辦,每一題都沒有答案。今天用 HermesAgent(Nous Research 的開源 agent)的實作把答案補上。
一輪裡模型可能同時丟出好幾個工具呼叫。全部串行安全但慢;全部並行會出事,兩個工具同時寫同一個檔案就是互相蓋寫。HermesAgent 的解法是靜態分類,工具在定義時就標好並行屬性:只讀無副作用的(read_file、web_search)永遠可並行;會寫檔案的(write_file、patch)路徑不重疊才並行;需要等使用者回應的(clarify)強制串行;沒分類過的未知工具一律串行,保守但正確。
被否決的替代方案是在 runtime 推斷工具能不能並行。靜態分類犧牲一點彈性,換到行為可預測:同一批工具進來,決策永遠相同,出問題能重現。
API 呼叫失敗就 retry,是 loop 裡最常見的壞直覺。429(限流,請求太頻繁被暫時拒絕)要等冷卻或換金鑰再試;context 超長被拒絕,要先壓縮再試;402 額度耗盡,retry 只是繼續撞牆;400 請求格式錯,retry 會得到一模一樣的錯。每種失敗的正確動作都不同,所以 HermesAgent 在 retry 之前先過一個分類器,回傳三個 flag:可不可以重試、要不要先壓縮 context、要不要換一把金鑰,loop 照著 flag 行動。
一個消歧細節值得單獨看:402 可能是額度真的耗盡(不可重試),也可能是暫時性的配額重置,幾分鐘後就好(可重試)。區分方法是看 error message 有沒有「try again in N minutes」這類暫時性信號。這種判斷在 demo 裡永遠不會觸發,在 24/7 運轉的系統裡,誤判一次就是白白停機或白白燒錢。
設計好的 loop 有三個明確的出口。正常完成:模型的回應裡沒有 tool_calls,它認為任務結束。預算耗盡:迭代數到達上限(HermesAgent 預設 90 輪),到頂時先讓模型摘要「做了什麼、卡在哪、還剩什麼」再返回,呼叫方永遠拿得到有意義的回覆,而非一個 timeout。外部中斷:使用者或監控喊停,loop 在下一個安全點退出。
介入又分兩種語義。interrupt 是立刻停:訊號廣播到所有並行工具的執行緒,並遞迴傳給所有子 agent。steer 是只轉向:把一句話附在最近的工具結果後面,工具照跑,模型下一輪看到訊息自己調整。單一 agent 時差異不明顯,父 agent 帶著一群子 agent 跑長任務時,「全部取消」和「修個方向」是兩顆完全不同的按鈕。
前面講 loop 內部,最後一題在外面:這整個 loop,對系統的其他部分來說是什麼?寫成一個「呼叫、等待、返回」的長函式,第一天最快。但互動需求一出現,形狀就撐不住了:停止按鈕要求 loop 可取消,而且取消後已生成的內容要保留;使用者關掉分頁再回來,要求執行不能綁在 HTTP 連線的生命週期上;危險操作先暫停等批准,要求狀態能落地、之後能恢復。三個需求收斂成同一個答案:一次執行(run)是一個有狀態、可查詢、可取消的狀態機,事件即時落地,連線只是觀看視窗,斷了再開一個從斷點續播。這跟 Day 16(Session 設計)的 durable 路線是同一個決策在不同尺度的重演:session 讓對話活過 process,run 狀態機讓單次執行活過連線。
適用邊界:內部 batch 任務、沒有人在畫面前等,長函式完全夠用。判斷點一句話:有沒有人要在執行中途看到它、介入它?
收攏今天的共同邏輯:loop 的每一個出口、每一種失敗,都有事先定義好的去處。並行分類讓執行可預測,錯誤分類讓每種失敗有對的動作,三個停止條件保證 loop 在任何情況下都收得了尾,interrupt 和 steer 讓外面的人管得住裡面的執行。
還有一類問題今天刻意沒碰:錯誤最終要見人。額度用盡要怎麼告訴使用者、危險操作要等誰批准、哪些失敗該無聲消化、哪些該誠實承認,這些答案在機制之外,在體驗和信任的層面。明天講 harness 最嚴肅的一塊:錯誤哲學與三條信任邊界。